home *** CD-ROM | disk | FTP | other *** search
- ;*****************************************************************************
- ; PROGRAM ----: NWBCAST.ASM, version 1.0
- ; AUTHOR -----: Kevin E. Saffer, 904-296-9000 Days EST, 262-1020 Evenings
- ; COPYRIGHT --: None, placed into the public domain
- ; CREATED ----: 1/22/1994 at 13:04
- ;*****************************************************************************
- ; Introduction:
- ; -------------
- ; Implements a software interrupt service routine for the Novell shell
- ; versions 3.01 and above. The interrupt handler will insert a programmer
- ; specified keystroke into the PC's keyboard buffer whenever a broadcast
- ; message is detected. The Clipper application may then handle this event
- ; by defining a SET KEY procedure tied to the keystroke specified in the
- ; install routine. The Clipper procedure may then use the NETTO functions
- ; to handle the incoming message.
- ;
- ; Warning: This routine installs a ISR (interrupt service routine) which
- ; MUST be removed before program exit by calling the uninstall
- ; function. Leaving the ISR active after program completion will
- ; cause the computer to transfer control to an incorrect address
- ; the next time a broadcast message is detected. This will most
- ; likely result in a locked up PC. A future version can be built
- ; as a small TSR loaded before the Clipper application. This will
- ; allow the routine to remain in memory even if the Clipper pgm
- ; crashes. An interface module will be linked into the Clipper
- ; application to communicate with the TSR. After this release is
- ; debugged, I'll get to work on the TSR version.
- ;
- ; Since an ISR is used, this module may never be overlayed. The ISR code
- ; must always be available to handle the interrupt, therefore this object
- ; file must be placed into the root portion of your link script. It will
- ; only increase the load size of the application by 700 bytes.
- ;
- ; Compatibility:
- ; --------------
- ; Netware shell versions 3.01 and above will issue an INT 2F whenever a
- ; broadcast message is waiting. For this reason, the latest shells must be
- ; used; they are available for downloading on the Compuserve NOVLIB forum.
- ;
- ; This routine will not work with the DOS extenders from CA or Blinker. The
- ; reason it will not work is that I have no idea how to switch these routines
- ; from segment addressing over to protected mode addressing. If anyone has
- ; this knowledge, please share it on the forum or call me directly.
- ;
- ; Usage Restrictions:
- ; -------------------
- ; Should you wish to shell out of the Clipper application, this routine must
- ; be shut down using NB_STOP() prior to running other programs. If left
- ; active, any broadcast message will cause the specified keystroke to be
- ; fed into the shelled program. Re-start the routine using NB_START() when
- ; the Clipper application regains control.
- ;
- ; Messages Must Be Allowed! (CASTON)
- ; ----------------------------------
- ; Before use, you should change the Netware shell's brodcast mode to 0 to
- ; allow normal broadcast message handling. This routine will then prevent
- ; the message from being displayed on the last display line. Use the NETTO
- ; function FN_SETBMOD( 0 ) to accomplish this, or ensure CASTON has been
- ; executed prior to loading your application.
- ;
- ; Compiling/Linking:
- ; ------------------
- ; Compile with MASM 5.1 or greater using "MASM nwbcast;"
- ; Link the resulting NWBCAST.OBJ into your application at the root level.
- ;
- ;*****************************************************************************
- ; Clipper callable function list:
- ;*****************************************************************************
- ;
- ; NB_START( <key> ) - installs the interrupt service routine with specified key
- ; NB_STOP() - removes the interrupt service routine
- ; NB_SERVER() - returns the connection ID of the server holding the last message
- ;
- ;*****************************************************************************
- .RADIX 16 ; my family has 8 fingers per hand so we think in HEX! <g>
-
- ; declare callable routines as public
- PUBLIC NB_START ; installation routine
- PUBLIC NB_STOP ; uninstallation routine
- PUBLIC NB_SERVER ; last message server connection number
-
- ; declare clipper parameter routines
- EXTRN __PARC:FAR ; get character string, segment:offset in DX:AX
- EXTRN __PARCLEN:FAR ; get length of a string parameter into ax
- EXTRN __PARCSIZ:FAR ; get size of memory allocated for string parameter
- EXTRN __PARDS:FAR ; get date string, segment:offset in DX:AX
- EXTRN __PARINFA:FAR ; get size of array parameter or element type
- EXTRN __PARINFO:FAR ; get number of parameters or type of one
- EXTRN __PARL:FAR ; get logical, value in AX
- EXTRN __PARND:FAR ; get numeric double, segment:offset in DX:AX
- EXTRN __PARNI:FAR ; get numeric integer, value in AX
- EXTRN __PARNL:FAR ; get numeric long, value in DX:AX
- EXTRN __RETC:FAR ; return string, push seg:off onto stack
- EXTRN __RETCLEN:FAR ; return string of x length, push seg:off:length
- EXTRN __RETDS:FAR ; return date string, push seg:off onto stack
- EXTRN __RETL:FAR ; return logical, push 1 register onto stack
- EXTRN __RETND:FAR ; return double, push 4 registers onto stack
- EXTRN __RETNI:FAR ; return integer, push 1 register onto stack
- EXTRN __RETNL:FAR ; return long, push 2 registers onto stack
-
- ; define a keyboard buffer structure for the insertion routine
- BIOS_DATA SEGMENT AT 40
- ORG 1A
- BUFFER_HEAD DW ? ; pointer to the keybord buffer head
- BUFFER_TAIL DW ? ; pointer to the keyboard buffer tail
- ORG 80
- BUFFER_START DW ? ; starting keyboard buffer address
- BUFFER_END DW ? ; ending keyboard buffer address
- BIOS_DATA ENDS
-
- ; declare our code segment
- CODE SEGMENT 'CODE'
- ASSUME CS:CODE,DS:CODE ; inform MASM of our intentions
-
- OLDINTSEG DW 0 ; old 2F vector segment
- OLDINTOFF DW 0 ; old 2F vector offset
- KEYCODE DW 1 ; keyboard scan code to be inserted (this is Ctrl-A)
- SERVERID DW 0 ; server connection number
-
- ;*****************************************************************************
- ; NB_START() - interrupt service routine installation
- ;*****************************************************************************
- NB_START PROC FAR
- PUSH BP ; save vital registers
- MOV BP,SP
- PUSH DS
- PUSH ES
-
- MOV AX,1 ; retrieve the keycode to be used
- PUSH AX
- CALL __PARNI
- MOV CS:KEYCODE,AX ; save it and restore the stack
- POP AX
-
- PUSH CS ; reset the data segment to point to our code segment
- POP DS
-
- CMP OLDINTSEG,0 ; check to see if the vector was already changed
- JZ NB_START1 ; no, proceed with vector change
-
- POP ES ; restore clipper registers
- POP DS
- POP BP
- CLD ; reset the direction flag
- RET ; return to clipper
-
- NB_START1:
- MOV AX,352F ; get interrupt vector 2F into ES:BX
- INT 21 ; call dos
- MOV OLDINTSEG,ES ; save the existing handler segment
- MOV OLDINTOFF,BX ; save the existing handler offset
- MOV WORD PTR [INTADDR+2],ES ; update ISR with existing segment
- MOV WORD PTR [INTADDR],BX ; update ISR with existing offset
-
- PUSH CS ; store the segment of new routine
- POP DS ; and place it into DS
- MOV DX,OFFSET NB_INT2F ; offset of the new routine to DX
- MOV AX,252F ; set interrupt vector 2F from DS:DX
- INT 21 ; call dos
-
- POP ES ; restore clipper registers
- POP DS
- POP BP
- CLD ; reset the direction flag
- RET ; return to clipper
-
- NB_START ENDP
-
- ;*****************************************************************************
- ; NB_STOP() - interrupt service routine uninstallation
- ;*****************************************************************************
- NB_STOP PROC FAR
- PUSH BP ; save vital registers
- MOV BP,SP
- PUSH DS
- PUSH ES
-
- PUSH CS ; reset the data segment to point to our code segment
- POP DS
-
- CMP OLDINTSEG,0 ; check to see if the vector had been changed
- JZ NB_STOP2 ; no, return to clipper
-
- MOV AX,OLDINTSEG ; retrieve old routine segment
- MOV DX,OLDINTOFF ; retrieve old routine offset
-
- PUSH AX ; store the segment of old routine
- POP DS ; and place it into DS
- MOV AX,252F ; set interrupt vector 2F from DS:DX
- INT 21 ; call dos
-
- MOV OLDINTSEG,0 ; clear the existing handler segment
- MOV OLDINTOFF,0 ; clear the existing handler offset
-
- NB_STOP2:
- POP ES ; restore clipper registers
- POP DS
- POP BP
- CLD ; reset the direction flag
- RET ; return to clipper
-
- NB_STOP ENDP
-
- ;*****************************************************************************
- ; NB_SERVER() - return the connection ID of the server holding the message
- ;*****************************************************************************
- NB_SERVER PROC FAR
- PUSH BP ; save vital registers
- MOV BP,SP
- PUSH DS
- PUSH ES
-
- MOV AX,CS:SERVERID ; retrieve the connection number
- PUSH AX
- CALL __RETNI
- POP AX
-
- POP ES ; restore clipper registers
- POP DS
- POP BP
- CLD ; reset the direction flag
- RET ; return to clipper
-
- NB_SERVER ENDP
-
- ;*****************************************************************************
- ; NB_INT2F - interrupt service routine
- ;*****************************************************************************
- NB_INT2F PROC NEAR
- PUSHF ; save calller's flags for the original interrupt 2F
- CMP AX,7A85 ; is a broadcast message is waiting?
- JE NB_INT2F1 ; yes, take over the interrupt
- JMP NB_INT2F4 ; no, transfer control to the original interrupt
-
- NB_INT2F1:
- PUSH AX ; save the registers used by this routine
- PUSH BX
- PUSH DX
- PUSH DS
-
- PUSH CS ; set DS to this segment
- POP DS
- CLD ; clear direction flag
- MOV CS:SERVERID,CX ; save the server connection number for later
- XOR CX,CX ; inform Netware we will handle the message
- MOV BX,BIOS_DATA ; point ds to the bios data area
- MOV DS,BX
- ASSUME DS:BIOS_DATA ; inform MASM of the new data segment
- CLI ; disable interrupts for buffer manipulation
- MOV BX,BUFFER_TAIL ; get buffer tail address
- MOV DX,BX ; transfer it to DX
- ADD DX,2 ; calculate next buffer position
- CMP DX,BUFFER_END ; did we overshoot the end?
- JNE NB_INT2F2 ; no, then continue
- MOV DX,BUFFER_START ; yes, then wrap to start of buffer
-
- NB_INT2F2:
- CMP DX,BUFFER_HEAD ; is the buffer full?
- JE NB_INT2F3 ; yes, then end now
- MOV AX,CS:KEYCODE ; retrieve the keycode
- MOV [BX],AX ; insert the keycode into the keyboard buffer
- MOV BX,DX ; advance the tail
- MOV BUFFER_TAIL,BX ; record its new position
-
- NB_INT2F3:
- STI ; enable interrupts
- POP DS ; restore registers
- POP DX
- POP BX
- POP AX
-
- NB_INT2F4:
- POPF ; restore the caller's flags
- DB 0EAH ; JMP FAR immediate opcode
- INTADDR DD 0 ; original int 2F address, updated by NB_START()
-
- NB_INT2F ENDP
-
- CODE ENDS ; end of segment
- END ; end of program